﻿using System.Collections.Generic;
using System.Runtime.Serialization;
using System;
using Flatland.GeneticProgramming.CoreTypes;

/**
* 
* Copyright (c) 2012 Anders Høst Kjærgaard | ahkj@itu.dk
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction, 
* including without limitation the rights to use, copy, modify, merge, publish, distribute, 
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial 
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

namespace Flatland.GeneticProgramming.Examples {

    /// <summary>
    /// MathExample2 shows how IExpression<T> could use logic.
    /// Here we use bool, but it could be any type.
    /// This example tries generates a program by a logical sentence that is true if it has exactly one true literal.
    /// The exeample is very contrieved,  and its main goal is to demonstrate how one can work with this.
    /// 
    /// Sample program with fitness 99 out of 100.
    ///public bool Execute2() {
    ///    return this.AND(this.NOT(this.AND(symbols[2], symbols[3])), 
    ///                    this.AND(this.NOT(this.AND(symbols[0], symbols[5])), 
    ///                             this.NOT(this.AND(symbols[7], symbols[7]))));
    /// 
    /// Which is equalivant to !(s2 AND s3) AND (!(s0 AND s5) AND !(s7 AND s7))
    ///                  note: falseConf1,5       falseConf4,5,6    All true conf.                    
    ///}
    /// </summary>
    [Serializable]
    public class MathExample2 : GenoType, IExpression<bool> {

        private const int Symbols = 8;

        /*
         * Training data 
         */
        private List<bool[]> trueConfigurations = new List<bool[]>
                                                      {
                                                          new[] {true,  false, false, false, false, false, false, false},
                                                          new[] {false, true,  false, false, false, false, false, false},
                                                          new[] {false, false, true,  false, false, false, false, false},
                                                          new[] {false, false, false, true,  false, false, false, false},
                                                          new[] {false, false, false, false, true,  false, false, false},
                                                          new[] {false, false, false, false, false, true,  false, false},
                                                          new[] {false, false, false, false, false, false, true,  false}
                                                      };

        private List<bool[]> falseConfigurations = new List<bool[]>
                                                      {
                                                          new[] { false, false, true,  true,  false, false, false, false },
                                                          new[] { false, false, false, false, false, false, false, false }, 
                                                          new[] { true,  false, false, false, false, false, false, true  },
                                                          new[] { true,  false, false, true,  false, true,  false, false },
                                                          new[] { true,  false, false, true,  false, true,  false, true  },
                                                          new[] { true,  true,  true,  true,  false, true,  false, false },
                                                          new[] { true,  false, false, true,  false, true,  true,  false }
                                                      };


        /// <summary>
        /// We check the expression on some training data a give points for correct answers.
        /// We want an expression that answers correct on all our training data - so
        /// fitness is given by the fitness goal minus wrong guesses.
        /// </summary>
        /// <returns></returns>
        public override double Fitness() {
            int wrongGuesses = 0;
            foreach (var trueConfiguration in trueConfigurations) {
                symbols = trueConfiguration;
                wrongGuesses += (bool) Execute() ? 0 : 1;
            }
            foreach (var falseConfiguration in falseConfigurations) {
                symbols = falseConfiguration;
                wrongGuesses += (bool) Execute() ? 1 : 0;
            }
            return GP.DEFAULT_FITNESS_GOAL - wrongGuesses;
        }


        /// <summary>
        /// A list of boolean. The genetic code will have its elements as variables.
        /// </summary>
        [Primitive]
        public bool[] symbols = new bool[Symbols];


        /** 
         * Logical operations.
         */
        [Primitive]
        public bool AND(bool a, bool b) {
            return a && b;
        }

        [Primitive]
        public bool OR(bool a, bool b) {
            return a || b;
        }

        [Primitive]
        public bool XOR(bool a, bool b) {
            return a | b;
        }

        [Primitive]
        public bool IMPL(bool a, bool b) {
            return !a || b;
        }

        [Primitive]
        public bool BI(bool a, bool b) {
            return AND(IMPL(a, b), IMPL(b, a));
        }

        [Primitive]
        public bool NOT(bool a) {
            return !a;
        }

        protected override void Act(ref string msg) {
            throw new System.NotImplementedException();
        }

           public MathExample2(SerializationInfo info, StreamingContext context) {}
        public MathExample2()
        {
        }

        public override object Clone()
        {
            return new MathExample2();
        }
    }
}

